package com.ndp.fb.walle.business.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.ndp.fb.exception.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.dubbo.config.annotation.Reference;
import com.google.common.collect.Lists;
import com.ndp.fb.enums.ErrorType;
import com.ndp.fb.enums.customaudience.CustomAudienceDataSourceSubType;
import com.ndp.fb.enums.customaudience.CustomAudienceDataSourceType;
import com.ndp.fb.enums.customaudience.CustomAudienceSubType;
import com.ndp.fb.enums.customaudience.FileType;
import com.ndp.fb.enums.customaudience.OperateType;
import com.ndp.fb.fbagent.service.CustomaudiencesFbServices;
import com.ndp.fb.model.CustomAudienceTemplateRoster;
import com.ndp.fb.model.business.bo.targetingspec.CustomAudience;
import com.ndp.fb.model.business.vo.cache.result.AudienceForPublish;
import com.ndp.fb.model.business.vo.cache.result.CustomAudienceCache;
import com.ndp.fb.model.fbagent.param.APIPriority;
import com.ndp.fb.model.fbagent.param.ApiCallBackTarget;
import com.ndp.fb.model.fbagent.param.customaudience.CustomAudienceParam;
import com.ndp.fb.model.fbagent.param.customaudience.CustomAudienceUserParam;
import com.ndp.fb.model.fbagent.param.entrustaccount.EntrustAccountParam;
import com.ndp.fb.model.fbagent.result.FBSuccess;
import com.ndp.fb.model.fbagent.result.common.FBSingleId;
import com.ndp.fb.mongo.api.CustomAudienceTemplateMongoService;
import com.ndp.fb.rdb.api.CustomAudienceRdbService;
import com.ndp.fb.rdb.api.CustomAudienceTemplateRdbService;
import com.ndp.fb.rdb.api.EntrustAccountConnectionObjectsRdbService;
import com.ndp.fb.rdb.api.FbUserRdbService;
import com.ndp.fb.rdb.model.EntrustAccount;
import com.ndp.fb.rdb.model.EntrustAccountConnectionObjects;
import com.ndp.fb.rdb.model.Pager;
import com.ndp.fb.rdb.model.User;
import com.ndp.fb.rdb.model.customaudience.CustomAudienceItem;
import com.ndp.fb.rdb.model.customaudience.CustomAudienceTemplate;
import com.ndp.fb.rdb.model.customaudience.CustomAudienceTemplateAccountCount;
import com.ndp.fb.rdb.model.customaudience.CustomAudienceTemplateAndConnectionObject;
import com.ndp.fb.rdb.model.customaudience.CustomAudienceTemplateConnectionObjectName;
import com.ndp.fb.rdb.model.customaudience.CustomAudienceTemplateTable;
import com.ndp.fb.util.ListUtil;
import com.ndp.fb.util.StringUtil;
import com.ndp.fb.walle.business.CacheService;
import com.ndp.fb.walle.business.CustomAudienceTemplateService;
import com.ndp.fb.walle.model.bo.customaudiencetemplate.result.CustomAudienceTemplateResult;
import com.ndp.fb.walle.model.vo.OutputResult;
import com.ndp.fb.walle.model.vo.customaudience.param.CustomAudienceDelParam;
import com.ndp.fb.walle.model.vo.customaudience.param.CustomAudienceTemplateParam;
import com.ndp.fb.walle.model.vo.customaudience.param.QueryLookALikeParam;
import com.ndp.fb.walle.util.FileUploadUtils;
import com.ndp.fb.walle.util.FormatValidateUtils;
import com.ndp.fb.walle.util.ResponseUtils;

/**
 * Created by Evan on 2015-12-12
 */
@Component
public class CustomAudienceTemplateServiceImpl implements CustomAudienceTemplateService {
    private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private CacheService cacheService;

    @Reference
    private CustomaudiencesFbServices customaudiencesFbServices;

    @Reference
    private CustomAudienceTemplateMongoService customAudienceTemplateMongoService;

    @Reference
    private CustomAudienceTemplateRdbService customAudienceTemplateRdbService;

    @Reference
    private FbUserRdbService fbUserRdbService;

    @Reference
    private CustomAudienceRdbService customAudienceRdbService;

    @Reference
    private EntrustAccountConnectionObjectsRdbService entrustAccountConnectionObjectsRdbService;

    @Override
    public List<AudienceForPublish> buildCustomAudienceCaches(List<EntrustAccount> entrustAccounts, Long appId) throws BusinessException {
        if (ListUtil.isEmpty(entrustAccounts)) {
            logger.warn("发广告阶段获取自定义受众：广告账号空");
            return null;
        }
        List<Long> fbAccountIds = new ArrayList<>();
        entrustAccounts.forEach(entrustAccount1 -> fbAccountIds.add(entrustAccount1.getFbAccountId()));
        return customAudienceRdbService.findPassedByAccountId(fbAccountIds, appId);
    }

    @Override
    public List<CustomAudienceCache> buildCustomAudienceCachesFBOK(List<EntrustAccount> entrustAccounts) throws BusinessException
    {
        if (ListUtil.isEmpty(entrustAccounts)) {
            return null;
        }
        List<CustomAudienceCache> customAudienceCaches = new ArrayList<>();
        CustomAudienceCache customAudienceCache;
        for (EntrustAccount entrustAccount : entrustAccounts) {
            List<Map<String, String>> customAudienceMaps = (List<Map<String, String>>) cacheService.fetchObject("customaudiences_" + entrustAccount.getFbAccountId());
            if (ListUtil.isEmpty(customAudienceMaps)) {
                continue;
            }

            customAudienceCache = new CustomAudienceCache();
            customAudienceCache.setFbAccountId(entrustAccount.getFbAccountId());
            customAudienceCache.setFbAccountName(StringUtils.isEmpty(entrustAccount.getName()) ? entrustAccount.getFbAccountId().toString() : entrustAccount.getName());
            CustomAudience customAudience;
            List<CustomAudience> customAudiences = new ArrayList<>();
            for (Map<String, String> customAudienceMap : customAudienceMaps) {
                customAudience = new CustomAudience();
                customAudience.setId(Long.valueOf(customAudienceMap.get("id")));
                customAudience.setName(customAudienceMap.get("name"));
                customAudiences.add(customAudience);
            }
            customAudienceCache.setCustomAudiences(customAudiences);
            customAudienceCaches.add(customAudienceCache);
        }
        return customAudienceCaches;
    }

    @Override
    public CustomAudienceCache buildEntrustAccountCustomAudienceCachesFBOK(Long entrustAccountId)
            throws BusinessException {
        List<Map<String, String>> customAudienceMaps = (List<Map<String, String>>) cacheService.fetchObject("customaudiences_" + entrustAccountId);
        if (ListUtil.isEmpty(customAudienceMaps)) {
            return null;
        }

        CustomAudienceCache customAudienceCache = new CustomAudienceCache();
        customAudienceCache.setFbAccountId(entrustAccountId);
        CustomAudience customAudience;
        List<CustomAudience> customAudiences = new ArrayList<>();
        for (Map<String, String> customAudienceMap : customAudienceMaps) {
            customAudience = new CustomAudience();
            customAudience.setId(Long.valueOf(customAudienceMap.get("id")));
            customAudience.setName(customAudienceMap.get("name"));
            customAudiences.add(customAudience);
        }
        customAudienceCache.setCustomAudiences(customAudiences);
        return customAudienceCache;
    }

    @Override
    public Pager<CustomAudienceTemplateResult> getLookAlikeList(QueryLookALikeParam queryLookALikeParam, User user, int firstResult, int sizeNo) {

        Long orgId = user.getOrgId();
        String userId = user.getTicket();
        String name = queryLookALikeParam.getName();

        List<CustomAudienceTemplateTable> customAudienceTemplateTableList = customAudienceTemplateRdbService.findAllLookAlikeByUserIdAndName(orgId,name);
        List<CustomAudienceTemplateAccountCount> customAudienceTemplateAccountCountList = customAudienceTemplateRdbService.findAllCustomAudienceTemplateIdAndAccountNum(userId);
        List<CustomAudienceTemplateAccountCount> customAudienceTemplateAvliableAccountCountList = customAudienceTemplateRdbService.findAllCustomAudienceTemplateIdAnAvaliableAccountNum(userId);

        Pager<CustomAudienceTemplateResult> pageResult = new Pager<CustomAudienceTemplateResult>();
        pageResult.setPageIndex(firstResult);
        pageResult.setPageSize(sizeNo);
        pageResult.setTotalSize(new Long(customAudienceTemplateTableList.size()));

        List<CustomAudienceTemplateResult> listResult = new ArrayList<CustomAudienceTemplateResult>();
        List<Long> templateIds = new ArrayList<Long>();

        //算出每个模板对应的账号总数
        getTempalteAccountNum(customAudienceTemplateAccountCountList, customAudienceTemplateTableList, listResult);

        //算出每个模板可用账号数
        getAvaliableAccountNum(customAudienceTemplateAvliableAccountCountList, listResult, templateIds);

        //算出每个模板对应的应用名称
        getTemplateAppName(listResult, templateIds);

        ArrayList<CustomAudienceTemplateResult> customAudienceTemplateResults = new ArrayList<>();

        //移除掉总数为零的模板
        removeZeroTempate(pageResult, listResult, customAudienceTemplateResults);

        //内存分页
        List<CustomAudienceTemplateResult> pageList = new ArrayList<CustomAudienceTemplateResult>();
        if(firstResult < customAudienceTemplateResults.size()){
            for(int i = firstResult,j = 0; i < customAudienceTemplateResults.size(); i++){
                if(j < sizeNo){
                    pageList.add(customAudienceTemplateResults.get(i));
                }
                j++;
            }
        }
        pageResult.setResultList(pageList);
        return pageResult;
    }

    @Override
    public Pager<CustomAudienceTemplateResult> getCustomAudienceTemplateList(Long orgId,String userId, String audienceType, String importedType, int firstResult, int sizeNo) {

        List<CustomAudienceTemplateTable> customAudienceTemplateList = customAudienceTemplateRdbService.getAllCustomAudienceTemplate(orgId, audienceType, importedType);
        List<CustomAudienceTemplateAccountCount> customAudienceTemplateAccountCountList = customAudienceTemplateRdbService.findAllCustomAudienceTemplateIdAndAccountNum(userId);
        List<CustomAudienceTemplateAccountCount> customAudienceTemplateAvaliableAccountCountList = customAudienceTemplateRdbService.findAllCustomAudienceTemplateIdAnAvaliableAccountNum(userId);

        Pager<CustomAudienceTemplateResult> pageResult = new Pager<CustomAudienceTemplateResult>();
        pageResult.setPageIndex(firstResult);
        pageResult.setPageSize(sizeNo);
        pageResult.setTotalSize(new Long(customAudienceTemplateList.size()));

        List<CustomAudienceTemplateResult> listResult = new ArrayList<CustomAudienceTemplateResult>();
        List<Long> templateIds = new ArrayList<Long>();

        //算出每个模板对应的账号总数
        getTempalteAccountNum(customAudienceTemplateAccountCountList, customAudienceTemplateList, listResult);

        //算出每个模板可用账号数
        getAvaliableAccountNum(customAudienceTemplateAvaliableAccountCountList, listResult, templateIds);

        //算出每个模板对应的应用名称
        listResult = getTemplateAppName(listResult, templateIds);

        //自定义受众模板结果
        ArrayList<CustomAudienceTemplateResult> customAudienceTemplateResults = new ArrayList<>();

        //移除掉总数为零的模板
        removeZeroTempate(pageResult, listResult, customAudienceTemplateResults);

        //内存分页
        List<CustomAudienceTemplateResult> pageList = new ArrayList<CustomAudienceTemplateResult>();
        if(firstResult < customAudienceTemplateResults.size()){
            for(int i = firstResult,j = 0; i < customAudienceTemplateResults.size(); i++){
                if(j < sizeNo){
                    pageList.add(customAudienceTemplateResults.get(i));
                }
                j++;
            }
        }

        pageResult.setResultList(pageList);
        return pageResult;
    }

    private void removeZeroTempate(Pager<CustomAudienceTemplateResult> pageResult, List<CustomAudienceTemplateResult> listResult, ArrayList<CustomAudienceTemplateResult> customAudienceTemplateResults) {
        for(CustomAudienceTemplateResult result :listResult){
            Integer accountNum = result.getAccountNum();
            if(accountNum.intValue() == 0){
                pageResult.setTotalSize(pageResult.getTotalSize() - 1);
                continue;
            }
            customAudienceTemplateResults.add(result);
        }
    }

    private List<CustomAudienceTemplateResult> getTemplateAppName(List<CustomAudienceTemplateResult> listResult, List<Long> templateIds) {
        List<CustomAudienceTemplateResult> customAudienceTemplateResults = new ArrayList<CustomAudienceTemplateResult>();
        if (ListUtil.isNotEmpty(templateIds)) {
            //根据模板ID查询模板对应的应用
            List<CustomAudienceTemplateConnectionObjectName> customAudienceTemplateConnectionObjectNameList = customAudienceTemplateRdbService.findConnectionObjectNameByTempladteIds(templateIds);
            for (CustomAudienceTemplateResult result : listResult) {
                StringBuffer appNameSb = new StringBuffer();
                boolean flag = false;
                for (CustomAudienceTemplateConnectionObjectName customAudienceTemplateConnectionObjectName : customAudienceTemplateConnectionObjectNameList) {
                    if (result.getId().equals(customAudienceTemplateConnectionObjectName.getCustomAudienceTemplateId())) {
                        flag = true;
                        appNameSb.append(customAudienceTemplateConnectionObjectName.getConnectionObjectName());
                        appNameSb.append(",");
                    }
                }
                if(flag){
                    String appName = appNameSb.toString();
                    int index = appName.lastIndexOf(',');
                    if (index != -1) {
                        appName = appName.substring(0, index);
                    }
                    result.setAppSource(appName);
                    customAudienceTemplateResults.add(result);
                }
            }
        }
        return customAudienceTemplateResults;
    }

    private void getAvaliableAccountNum(List<CustomAudienceTemplateAccountCount> customAudienceTemplateAvliableAccountCountList, List<CustomAudienceTemplateResult> listResult, List<Long> templateIds) {
        for (CustomAudienceTemplateResult result : listResult) {
            boolean isFound = false;
            for (CustomAudienceTemplateAccountCount customAudienceTemplateAccountCount : customAudienceTemplateAvliableAccountCountList) {
                if (result.getId().equals(customAudienceTemplateAccountCount.getCustomAudienceTemplateId())) {
                    isFound = true;
                    result.setAvailableAccountNum(customAudienceTemplateAccountCount.getNum());
                    break;
                }
            }
            if (!isFound) {
                result.setAvailableAccountNum(0);
            }
            templateIds.add(result.getId());
        }
    }

    private void getTempalteAccountNum(List<CustomAudienceTemplateAccountCount> customAudienceTemplateAccountCountList, List<CustomAudienceTemplateTable> list, List<CustomAudienceTemplateResult> listResult) {
        //算出每个模板总账号数
        for (CustomAudienceTemplateTable customAudienceTemplateTable : list) {
            CustomAudienceTemplateResult customAudienceTemplateResult = new CustomAudienceTemplateResult();
            customAudienceTemplateResult.setName(customAudienceTemplateTable.getName());
            customAudienceTemplateResult.setAccountNum(0);
            customAudienceTemplateResult.setCreator(customAudienceTemplateTable.getCreator());
            customAudienceTemplateResult.setApproximateCount(customAudienceTemplateTable.getApproximateCount());
            customAudienceTemplateResult.setTimeUpdated(customAudienceTemplateTable.getTimeUpdated());
            customAudienceTemplateResult.setId(customAudienceTemplateTable.getId());
            for (CustomAudienceTemplateAccountCount customAudienceTemplateAccountCount : customAudienceTemplateAccountCountList) {
                if (customAudienceTemplateTable.getId().equals(customAudienceTemplateAccountCount.getCustomAudienceTemplateId())) {
                    customAudienceTemplateResult.setAccountNum(customAudienceTemplateAccountCount.getNum());
                    break;
                }
            }
            listResult.add(customAudienceTemplateResult);
        }
    }

    @Override
    public int saveCustomAudience(MultipartFile multipartFile, String contextPath, CustomAudienceTemplateParam customAudienceTemplateParam, String userId,Long orgId) throws FormatException, IOException, ParamException, AudienceSizeIsNotEnoughException, NotSupportFileSuffixException {
        try {

            if(customAudienceTemplateParam.getAppIdList() == null ||(customAudienceTemplateParam.getAppIdList()!=null && customAudienceTemplateParam.getAppIdList().size() == 0)){
                throw new ParamException();
            }

            File file = null;
            List<String> lineList = null;
            if (multipartFile != null) {
                file = FileUploadUtils.multipartFile2File(multipartFile, contextPath);
                String originalFilename = multipartFile.getOriginalFilename();
                int index = originalFilename.lastIndexOf(".");
                if (index != -1) {
                    String suffix = originalFilename.substring(index + 1, originalFilename.length());
                    if (suffix == null || !(suffix.equals("txt") || suffix.equals("csv"))) {
                        throw new NotSupportFileSuffixException();
                    }
                }
            }

            String customAudienceDataSourceSubType;
            FileType fileType = FileType.valueOf(customAudienceTemplateParam.getImportedType());
            switch (fileType) {
                case APP_USER:
                    lineList = analysisFbUserIdFile(file, customAudienceTemplateParam.getContent(), customAudienceTemplateParam.getDeliverType());
                    customAudienceDataSourceSubType = CustomAudienceDataSourceSubType.USER_IDS.getType();
                    break;
                default:
                    customAudienceDataSourceSubType = "";
            }
            if (lineList == null || lineList.size() < 30) {
                throw new AudienceSizeIsNotEnoughException();
            }
            //保存自定义受众模板
            List<Long> connectionObjectIdList = customAudienceTemplateParam.getAppIdList();
            if (ListUtil.isNotEmpty(connectionObjectIdList)) {
                CustomAudienceTemplate customAudienceTemplate = new CustomAudienceTemplate();
                Long customAudienceTemplateId = saveCustomAudienceTemplate(customAudienceTemplateParam, userId, customAudienceDataSourceSubType, customAudienceTemplate);
                customAudienceTemplateParam.setCustomAudienceTempateId(customAudienceTemplateId);
                for (Long connnectionObjectId : connectionObjectIdList) {
                    syncConnectionEntrustAccountCustomTemplate(connnectionObjectId, orgId,userId, lineList, customAudienceDataSourceSubType, customAudienceTemplate, customAudienceTemplateId);
                }
            }
            if (file != null && file.exists()) {
                file.delete();
            }
            return lineList == null ? 0 : lineList.size();
        } catch (FormatException ex) {
            throw ex;
        } catch (IOException ioex) {
            throw ioex;
        } catch (ParamException pex) {
            throw pex;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 同步应用账号到自定义受众模板
     *
     * @param connectionObjectId
     * @param userId
     * @param lineList
     * @param customAudienceDataSourceSubType
     * @param customAudienceTemplate
     * @param customAudienceTemplateId
     */
    private void syncConnectionEntrustAccountCustomTemplate(Long connectionObjectId,Long orgId, String userId, List<String> lineList, String customAudienceDataSourceSubType, CustomAudienceTemplate customAudienceTemplate, Long customAudienceTemplateId) {
        List<EntrustAccountConnectionObjects> entrustAccountConnectionObjectsList = entrustAccountConnectionObjectsRdbService.findEntrustAccountsByFbConnectionObjectId(userId,orgId,connectionObjectId);
        if (entrustAccountConnectionObjectsList != null && entrustAccountConnectionObjectsList.size() > 0) {
            String version = String.valueOf(0);
            if (ListUtil.isNotEmpty(lineList)) {
                saveCusomAudienceTemplateRoster(userId, lineList, customAudienceDataSourceSubType, customAudienceTemplateId, version);
            }
            saveCustomAudienceFbAccount(entrustAccountConnectionObjectsList, version, customAudienceTemplate, userId);
        }
    }

    /**
     * 保存自定义受众模板成员到mongodb
     *
     * @param userId
     * @param lineList
     * @param customAudienceDataSourceSubType
     * @param customAudienceTemplateId
     * @param version
     */
    private void saveCusomAudienceTemplateRoster(String userId, List<String> lineList, String customAudienceDataSourceSubType, Long customAudienceTemplateId, String version) {
        List<CustomAudienceTemplateRoster> customAudienceTemplateRosterList = new ArrayList<CustomAudienceTemplateRoster>();
        for (String str : lineList) {
            CustomAudienceTemplateRoster customAudienceTemplateRoster = new CustomAudienceTemplateRoster();
            customAudienceTemplateRoster.setType(customAudienceDataSourceSubType);
            customAudienceTemplateRoster.setValue(str);
            customAudienceTemplateRosterList.add(customAudienceTemplateRoster);
        }
        //保存自定义受众用户列表
        customAudienceTemplateMongoService.saveCustomAudienceTemplateRoster(customAudienceTemplateId, customAudienceTemplateRosterList);
        //保存自定义受众历史
        customAudienceTemplateMongoService.saveCustomAudienceRosterHistory(customAudienceTemplateId, version, OperateType.ADD, userId, customAudienceTemplateRosterList);
    }

    /**
     * 保存自定义受众模板
     *
     * @param customAudienceTemplateParam
     * @param userId
     * @param customAudienceDataSourceSubType
     * @param customAudienceTemplate
     * @return
     * @throws ParamException
     */
    private Long saveCustomAudienceTemplate(CustomAudienceTemplateParam customAudienceTemplateParam, String userId, String customAudienceDataSourceSubType, CustomAudienceTemplate customAudienceTemplate) throws ParamException {
        if (customAudienceTemplateParam.getAppIdList() != null && customAudienceTemplateParam.getAppIdList().size() > 0) {
            customAudienceTemplate.setAudienceType(customAudienceTemplateParam.getAudienceType());
            customAudienceTemplate.setImportedType(customAudienceTemplateParam.getImportedType());
            customAudienceTemplate.setDataSourceType(CustomAudienceDataSourceType.FILE_IMPORTED.getType());
            customAudienceTemplate.setDataSourceSubtype(customAudienceDataSourceSubType);
            customAudienceTemplate.setApproximateCount(0l);
            customAudienceTemplate.setIsDelete(0);
            customAudienceTemplate.setScale("0");
            customAudienceTemplate.setDescription("");
            customAudienceTemplate.setTimeUpdated(System.currentTimeMillis());
            customAudienceTemplate.setTimeCreated(System.currentTimeMillis());
            customAudienceTemplate.setTimeContentUpdated(System.currentTimeMillis());
            customAudienceTemplate.setName(customAudienceTemplateParam.getAudienceName());
            customAudienceTemplate.setRetentionDays(180);
            customAudienceTemplate.setUserId(userId);
            customAudienceTemplate.setSubtype(CustomAudienceSubType.CUSTOM.getType());
            Long customAudienceTemplateId = customAudienceTemplateRdbService.save(customAudienceTemplate);
            customAudienceTemplateRdbService.batchSaveCustomAudienceTemplateAppRelation(customAudienceTemplateId, customAudienceTemplateParam.getAppIdList());
            customAudienceTemplate.setId(customAudienceTemplateId);
            return customAudienceTemplateId;
        } else {
            throw new ParamException();
        }
    }

    /**
     * 重试创建受众
     * @param tmplId
     * @param fbAccountId
     */
    public void retryCustomAudience(Long tmplId, Long fbAccountId, Long customAudienceDbId, String userId) {
        CustomAudienceTemplate customAudienceTemplate = customAudienceTemplateRdbService.findById(tmplId+"");
        String appIds = getAppIds(tmplId);
        Map<String, String> equipment = new HashMap<>();
        equipment.put("id", String.valueOf(customAudienceDbId));
        equipment.put("tmplid", String.valueOf(customAudienceTemplate.getId()));
        equipment.put("accountId", String.valueOf(fbAccountId));
        equipment.put("datasourcetype", customAudienceTemplate.getDataSourceType());
        equipment.put("appids", appIds);
        equipment.put("datasourcesubtype", customAudienceTemplate.getDataSourceSubtype());
        String token = fbUserRdbService.getTokenByUserId(userId);
        if(StringUtil.isNotEmpty(token))
        {
            equipment.put("accesstoken", token);
            equipment.put("name", customAudienceTemplate.getName());
            equipment.put("subtype", customAudienceTemplate.getSubtype());
            CustomAudienceParam param = new CustomAudienceParam();
            param.setAccessToken(token);
            param.setFbAccountId(fbAccountId);
            param.setName(customAudienceTemplate.getName());
            if(StringUtil.isNotEmpty(customAudienceTemplate.getDescription()))
                param.setDescription(customAudienceTemplate.getDescription());
            param.setSubtype(customAudienceTemplate.getSubtype());
            param.setResultClassName(FBSingleId.class.getName());
            param.setCallBack(true);
            param.setApiCallbackTargetType(ApiCallBackTarget.CustomAudience.AddCustomaudience.getTargetType());
            param.setApiPriorityCode(APIPriority.FetchCustomaudiences.getCode());
            param.setEquipment(equipment);
            customaudiencesFbServices.createCustomAudience(param);
        }
        else
        {
            logger.info("用户"+userId+"去重试自定义受众没有广告账号的token"+fbAccountId);
        }
    }

    private void sendCustomAudienceToFB(CustomAudienceTemplate customAudienceTemplate, EntrustAccountConnectionObjects account, Long id, String userId) {
        /**
         * 这个广告账号是否同意了fb相关法律法规
         * 1、customAudienceTos = 1 同意了  直接去fb创建自定义受众
         * 2、customAudienceTos = 0 or null 未同意 先去发送同意请求再创建自定义受众
         */
        String appIds = getAppIds(customAudienceTemplate.getId());
        Map<String, String> equipment = new HashMap<>();
        equipment.put("id", String.valueOf(id));
        equipment.put("tmplid", String.valueOf(customAudienceTemplate.getId()));
        equipment.put("accountId", String.valueOf(account.getFbAccountId()));
        equipment.put("datasourcetype", customAudienceTemplate.getDataSourceType());
        equipment.put("appids", appIds);
        equipment.put("datasourcesubtype", customAudienceTemplate.getDataSourceSubtype());
        if(account != null && account.getCustomAudienceTos() == 1)
        {
            String token = fbUserRdbService.getTokenByUserId(userId);
            if(StringUtil.isNotEmpty(token))
            {
                equipment.put("accesstoken", token);
                equipment.put("name", customAudienceTemplate.getName());
                equipment.put("subtype", customAudienceTemplate.getSubtype());
                CustomAudienceParam param = new CustomAudienceParam();
                param.setAccessToken(token);
                param.setFbAccountId(account.getFbAccountId());
                param.setName(customAudienceTemplate.getName());
                if(StringUtil.isNotEmpty(customAudienceTemplate.getDescription()))
                    param.setDescription(customAudienceTemplate.getDescription());
                param.setSubtype(customAudienceTemplate.getSubtype());
                param.setResultClass(FBSingleId.class);
                param.setCallBack(true);
                param.setApiCallbackTargetType(ApiCallBackTarget.CustomAudience.AddCustomaudience.getTargetType());
                param.setApiPriorityCode(APIPriority.FetchCustomaudiences.getCode());
                param.setEquipment(equipment);
                customaudiencesFbServices.createCustomAudience(param);
            }
            else
            {
                logger.info("用户"+userId+"去创建自定义受众没有广告账号的token"+account.getFbAccountId());
            }
        }
        else
        {
            String adminToken = fbUserRdbService.getTokenByUserId(userId);
            //String adminToken = adaccountsSchedulerService.getAdminTokenByFbActId(account.getFbAccountId()); //先不用admintoken
            if(StringUtil.isNotEmpty(adminToken))
            {
                equipment.put("accesstoken", adminToken);
                EntrustAccountParam entrustAccountParam = new EntrustAccountParam();
                entrustAccountParam.setFbAccountId(account.getFbAccountId());
                entrustAccountParam.setRemoveAccountFromUrl(true);
                entrustAccountParam.setTosAccepted("{\"custom_audience_tos\":1}");
                entrustAccountParam.setAccessToken(adminToken);
                entrustAccountParam.setCallBack(true);
                entrustAccountParam.setApiPriorityCode(APIPriority.GetEntrustAccounts.getCode());
                entrustAccountParam.setResultClass(FBSuccess.class);
                entrustAccountParam.setApiCallbackTargetType(ApiCallBackTarget.CustomAudience.AccountAgree.getTargetType());
                equipment.put("name", customAudienceTemplate.getName());
                equipment.put("subtype", customAudienceTemplate.getSubtype());
                if(StringUtil.isNotEmpty(customAudienceTemplate.getDescription()))
                    equipment.put("description", customAudienceTemplate.getDescription());
                entrustAccountParam.setEquipment(equipment);
                customaudiencesFbServices.agreeeCustomAudienceItem(entrustAccountParam);

            }
            else
            {
                logger.info("用户"+userId+"去创建授权自定义受众没有广告账号的token"+account.getFbAccountId());
            }
        }

    }

    private String getAppIds(Long tmplId) {
        List<CustomAudienceTemplateAndConnectionObject> customAudienceTemplateAndConnectionObjectList = customAudienceTemplateRdbService.getConnectionObjectIdByAudienceTemeplateId(tmplId);
        if(ListUtil.isEmpty(customAudienceTemplateAndConnectionObjectList))
            return "";
        StringBuffer appIds = new StringBuffer();
        int i = 0;
        for (CustomAudienceTemplateAndConnectionObject customAudienceTemplateAndConnectionObject : customAudienceTemplateAndConnectionObjectList) {
            appIds.append(customAudienceTemplateAndConnectionObject.getConnectionObjectId());
            if (i <= customAudienceTemplateAndConnectionObjectList.size() - 1) {
                appIds.append(",");
            }
            i++;
        }
        return appIds.toString();
    }

    /**
     * 保存自定义受众并发送到facebook
     *
     * @param accountIds
     * @param version
     * @param customAudienceTemplate
     */
    private void saveCustomAudienceFbAccount(List<EntrustAccountConnectionObjects> accountIds, String version, CustomAudienceTemplate customAudienceTemplate, String userId) {
        List<CustomAudienceItem> customAudienceList = new ArrayList<>();
        if (ListUtil.isNotEmpty(accountIds)) {
            for (int i = 0; i < accountIds.size(); i++) {
                CustomAudienceItem customAudience = new CustomAudienceItem();
                customAudience.setCustomAudienceId(-1l);
                customAudience.setRequestQueueStatus(0);
                customAudience.setDeliveryStatusCode(-1);
                customAudience.setOperationStatusCode(-1);
                customAudience.setFbAccountId(accountIds.get(i).getFbAccountId());
                customAudience.setCustomAudienceTemplateId(customAudienceTemplate.getId());
                customAudience.setDeliveryStatusDescription("");
                customAudience.setTimeCreated(System.currentTimeMillis());
                customAudience.setTimeUpdated(System.currentTimeMillis());
                customAudience.setOperationStatusDescription("");
                customAudience.setVersion(version);
                customAudienceList.add(customAudience);
            }
            try{
                List<Long> ids = customAudienceRdbService.batchSaveCustomAudience(customAudienceList);
                //去facebook创建自定义受众
                for (int x = 0; x < accountIds.size(); x++) {
                    sendCustomAudienceToFB(customAudienceTemplate, accountIds.get(x), ids.get(x), userId);
                }
            }catch (Exception ex){
                logger.error("save customaudience error:", ex);
            }
        }
    }


    /**
     * 解析按行读取fbUserId
     *
     * @param file
     * @return
     * @throws FormatException
     */
    private List analysisFbUserIdFile(File file, String content, String deliverType) throws FormatException {
        List<String> list = new ArrayList<>();
        if (deliverType != null && deliverType.equals("UPLOAD_TEXT_FILE")) {
            try {
                BufferedReader bw = new BufferedReader(new FileReader(file));
                String line = null;
                while ((line = bw.readLine()) != null) {
                    line = line.trim();
                    txtCsvAnalysisLineToList(line, list);
                }
                bw.close();
            } catch (FileNotFoundException e) {
                logger.error("file not found,", e);
            } catch (IOException ex) {
                logger.error("io exception");
            }
        } else {
            if (StringUtil.isNotEmpty(content)) {
                String[] records = content.split("\n|\r");
                for (int i = 0; i < records.length; i++) {
                    txtCsvAnalysisLineToList(records[i], list);
                }
            } else {
                logger.error("facebook app user id is empty:" + content);
                throw new FormatException();
            }
        }
        return list;
    }

    private void txtCsvAnalysisLineToList(String line, List<String> list) {
        if (line.indexOf(',') != -1) {
            String[] records = line.split(",");
            for (int i = 0; i < records.length; i++) {
                if (FormatValidateUtils.isNumeric(records[i])) {
                    list.add(records[i]);
                }
            }
        } else {
            if (FormatValidateUtils.isNumeric(line.trim())) {
                list.add(line.trim());
            }
        }
    }


    @Override
    public void del(CustomAudienceDelParam inParam, String userId) {
        if (inParam.getFlag() == 1) {
            delFBCustomAudience(inParam, userId);
        }
        //删除模板主表   更新is_delete
        customAudienceTemplateRdbService.delByIds(inParam.getIds(),ResourceMsgManager.getResource("zh_CN","CUSTOM_AUDIENCE_TEMPLATE_DEL_REASON_BY_USER"));
        //删除自定义受众表  更新is_delete
        customAudienceRdbService.delByTmplIds(inParam.getIds(), ResourceMsgManager.getResource("zh_CN","CUSTOM_AUDIENCE_DEL_REASON_BY_USER_DEL_CUSTOM_AUDIENCE_TEMPLATE"));
        //删除模板应用表  更新is_delete
        customAudienceTemplateRdbService.batchDelCustomAudienceTemplFbConnObjByTmplId(inParam.getIds());
    }

    @Override
    public void delLookAlike(CustomAudienceDelParam inParam, String userId) {
        if (inParam.getFlag() == 1) {
            delFBCustomAudience(inParam, userId);
        }
        //删除模板主表   更新is_delete
        customAudienceTemplateRdbService.delByIds(inParam.getIds(),ResourceMsgManager.getResource("zh_CN","CUSTOM_AUDIENCE_TEMPLATE_DEL_REASON_BY_USER_DEL_LOOKALIKE"));
        //删除自定义受众表  更新is_delete
        customAudienceRdbService.delByTmplIds(inParam.getIds(),ResourceMsgManager.getResource("zh_CN","CUSTOM_AUDIENCE_DEL_REASON_BY_USER_DEL_LOOKALIKE"));
    }

    private void delFBCustomAudience(CustomAudienceDelParam inParam, String userId) {
        List<CustomAudienceItem> customAudiences = customAudienceRdbService.findAllByTmplId(inParam.getIds());
            customAudiences.forEach(obj -> {
                if(obj.getCustomAudienceId()> 0){ //数据库默认值为-1，能够保证存在
                    CustomAudienceParam param = new CustomAudienceParam();
                    param.setId(obj.getCustomAudienceId());
                    String token = fbUserRdbService.getTokenByUserId(userId);
                    if(StringUtil.isNotEmpty(token))
                    {
                        param.setAccessToken(token);
                        param.setFbAccountId(obj.getFbAccountId());
                        customaudiencesFbServices.deleteCustomAudience(param);
                    }
                }
            });
    }

    @Override
    public OutputResult updateName(User user, Long templateId, String audienceName) {
        CustomAudienceTemplate customAudienceTemplate = customAudienceTemplateRdbService.findById(templateId + "");
        if (customAudienceTemplate == null) {
            return ResponseUtils.bulidOutputResult(ErrorType.NOT_FOUND_CustomAudience, null);
        }
//        if (customAudienceTemplate.getUserId().equals(user.getTicket())) {
            Date now = new Date();
            String version0 = now.getTime() + "";
            Long templateIdLong = templateId;
            List<CustomAudienceItem> customAudiences = customAudienceRdbService.findByTmplId(Lists.newArrayList(templateIdLong));
            if (StringUtils.isNoneEmpty(audienceName) && !audienceName.equals(customAudienceTemplate.getName())) {
                customAudienceTemplateRdbService.updateName(templateIdLong, audienceName);
                customAudienceTemplateMongoService.saveCustomAudienceNameRosterHistory(templateIdLong, version0, OperateType.ReName, user.getTicket(), audienceName);
                changeCustomAudienceName(customAudienceTemplate, audienceName, customAudiences, version0, user.getTicket());
            }
            return ResponseUtils.bulidOutputResult(null, null);
//        } else {
//            errorType = ErrorType.ACCOUNT_NOT_UPDATE_PRIVILEGE_CustomAudience;
//            return ResponseUtils.bulidOutputResult(errorType, null);
//        }
    }

    @Override
    public OutputResult update(User user, String templateId, MultipartFile multipartFile, String content, String contentPath,
                               String fileTypeString, String editType,String deliverType) throws Exception {
        CustomAudienceTemplate customAudienceTemplate = customAudienceTemplateRdbService.findById(templateId);
        if (customAudienceTemplate == null) {
            return ResponseUtils.bulidOutputResult(ErrorType.NOT_FOUND_CustomAudience, null);
        }

        Date now = new Date();
        String version1 = (now.getTime() + 1) + "";
        String version2 = (now.getTime() + 2) + "";
        String userId = user.getTicket();
        Long templateIdLong = Long.valueOf(templateId);

        String dataSourceType = customAudienceTemplate.getDataSourceType();
        String dataSourceSubtype = customAudienceTemplate.getDataSourceSubtype();

        fileTypeString = StringUtils.isNoneBlank(fileTypeString) ? fileTypeString : customAudienceTemplate.getImportedType();
        FileType fileType = FileType.valueOf(fileTypeString);

        List<String> lineList = null;
        if (multipartFile == null) {
            lineList = analysisFbUserIdFile(null, content, deliverType);
        } else {   //上传文件
            String originalFilename = multipartFile.getOriginalFilename();
            int index = originalFilename.lastIndexOf(".");
            if (index != -1) {
                String suffix = originalFilename.substring(index + 1, originalFilename.length());
                if (suffix == null || !(suffix.equals("txt") || suffix.equals("csv"))) {
                    throw new NotSupportFileSuffixException();
                }
            }
            File file = FileUploadUtils.multipartFile2File(multipartFile, contentPath);
            switch (fileType) {
                case APP_USER:
                    lineList = analysisFbUserIdFile(file, content, deliverType);
                    break;
            }
        }

        List<CustomAudienceTemplateRoster> rosters = new ArrayList<>();
        if (ListUtil.isNotEmpty(lineList)) {
            lineList.forEach((mapper) -> {
                CustomAudienceTemplateRoster customAudienceTemplateRoster = new CustomAudienceTemplateRoster();
                customAudienceTemplateRoster.setCustomAudienceId(templateIdLong);
                customAudienceTemplateRoster.setValue(mapper);
                customAudienceTemplateRoster.setType(fileType.getValue());
                rosters.add(customAudienceTemplateRoster);
            });
        }

        //有效内容少于30
        if (("add".equals(editType) || "replace".equals(editType) ) && rosters.size() < 30) {
            return ResponseUtils.bulidOutputResult(ErrorType.AUDIENCE_SIZE_NOT_ENOUGH_EXCEPTION, rosters.size());
        } else {
            customAudienceTemplateRdbService.updateOperationTime(templateIdLong);
            if ("add".equals(editType)) {
                customAudienceTemplateMongoService.saveCustomAudienceTemplateRoster(templateIdLong, rosters);
                customAudienceTemplateMongoService.saveCustomAudienceRosterHistory(templateIdLong, version1, OperateType.ADD, userId, rosters);
            } else if ("remove".equals(editType)) {
                customAudienceTemplateMongoService.deleteCustomAudienceTemplateRosters(templateIdLong, rosters);
                customAudienceTemplateMongoService.saveCustomAudienceRosterHistory(templateIdLong, version1, OperateType.REMOVE, userId, rosters);
            } else if ("replace".equals(editType)) { //替换
                List<CustomAudienceTemplateRoster> dbrosters = customAudienceTemplateMongoService.getCustomAudienceTemplateRoster(templateIdLong);
                customAudienceTemplateMongoService.deleteALlCustomAudienceTemplateRosters(templateIdLong);
                customAudienceTemplateMongoService.saveCustomAudienceTemplateRoster(templateIdLong, rosters);
                customAudienceTemplateMongoService.saveCustomAudienceRosterHistory(templateIdLong, version1, OperateType.REMOVE, userId, dbrosters);
                customAudienceTemplateMongoService.saveCustomAudienceRosterHistory(templateIdLong, version2, OperateType.ADD, userId, rosters);
                lineList = new ArrayList<>();
                for (CustomAudienceTemplateRoster dbroster : dbrosters) {
                    lineList.add(dbroster.getValue());
                }
            }


            String appIds = getAppIds(templateIdLong);

            String val = getCustomAudienceValString(dataSourceType, dataSourceSubtype, fileType.getValue(), appIds, lineList);
            List<CustomAudienceItem> customAudiences = customAudienceRdbService.findByTmplId(Lists.newArrayList(templateIdLong));
            for (CustomAudienceItem customAudience : customAudiences) {
                Long customAudienceId = customAudience.getCustomAudienceId();
                Long fbAccountId = customAudience.getFbAccountId();
                if(customAudience.getCustomAudienceId() == null || customAudienceId == -1L) {
                    logger.error("受众更新fbCustomAudienceId不能是-1，账号是："+fbAccountId);
                    continue;
                }
                customAudienceRdbService.updateVersionAndRequestQueueStatusAndFBStatus(customAudience.getId(), version1, 0);

                String token = fbUserRdbService.getTokenByUserId(userId);
                if(StringUtil.isNotEmpty(token)){
                    CustomAudienceUserParam audienceUserParam = new CustomAudienceUserParam();
                    Map<String, String> equipment = new HashMap<>();
                    equipment.put("templateId", templateId);
                    equipment.put("accesstoken", token);
                    equipment.put("customAudienceId", customAudienceId + "");
                    equipment.put("fbAccountId", customAudience.getFbAccountId() + "");
                    equipment.put("customAudienceDbId", customAudience.getId() + "");
                    equipment.put("templateId", templateId);
                    equipment.put("id", customAudienceId + "");
                    equipment.put("appId", appIds + "");
                    equipment.put("version", version1);
                    equipment.put("dataSourceSubtype", dataSourceSubtype);
                    equipment.put("dataSourceType", dataSourceType);
                    equipment.put("fileType", fileType.getValue());

                    if ("add".equals(editType)) {
                        audienceUserParam.setMethod("post");
                    } else if ("remove".equals(editType)) {
                        audienceUserParam.setMethod("delete");
                    } else if ("replace".equals(editType)) { //替换
                        equipment.put("next", "true");
                        equipment.put("nextVersion", version2);
                        equipment.put("nextMethod", "post");
                        audienceUserParam.setMethod("delete");
                    } else {
                        audienceUserParam.setMethod("post");
                    }
                    audienceUserParam.setEquipment(equipment);
                    audienceUserParam.setCallBack(true);
                    audienceUserParam.setApiCallbackTargetType(ApiCallBackTarget.CustomAudience.UpdateCustomAudienceUsers.getTargetType());
                    audienceUserParam.setApiPriorityCode(APIPriority.FetchCustomaudiences.getCode());
                    audienceUserParam.setId(customAudienceId + "");
                    audienceUserParam.setPayload(val);
                    audienceUserParam.setFbAccountId(fbAccountId);
                    audienceUserParam.setAccessToken(token);
                    customaudiencesFbServices.updateCustomAudienceUsers(audienceUserParam);
                } else {
                    logger.error("受众更新没有获取到token，账号是："+fbAccountId);
                }
            }
            return ResponseUtils.bulidOutputResult(null, rosters.size());
        }
    }

    private String getCustomAudienceValString(String dataSourceType, String dataSourceSubtype, String fileType,
                                              String appIds, List<String> customRosters) {
        StringBuffer sb = new StringBuffer();
        String schema;
        boolean isUid = false;
        switch (CustomAudienceDataSourceSubType.getType(dataSourceSubtype)) {
            case HASHES:
                if ("PHONE".equalsIgnoreCase(fileType))
                    schema = "PHONE_SHA256";
                else if ("EMAIL".equalsIgnoreCase(fileType))
                    schema = "EMAIL_SHA256";
                else
                    schema = "";
                break;
            case USER_IDS:
                schema = "UID";
                isUid = true;
                break;
            case MOBILE_ADVERTISER_IDS:
                schema = "MOBILE_ADVERTISER_ID";
                break;
            default:
                schema = "";
        }
        if (StringUtil.isEmpty(schema))
            return null;
        sb.append("{\"schema\":\"" + schema + "\",\"data\":[");
        for (int i = 0, len = customRosters.size(); i < len; i++) {
            if (CustomAudienceDataSourceSubType.HASHES.getType().equals(dataSourceSubtype))
                sb.append("\"").append(DigestUtils.sha256Hex(customRosters.get(i))).append("\"");
            else if (CustomAudienceDataSourceSubType.MOBILE_ADVERTISER_IDS.getType().equals(dataSourceSubtype))
                sb.append("\"").append(customRosters.get(i)).append("\"");
            else
                sb.append(customRosters.get(i));
            if (i < (len - 1))
                sb.append(",");
        }
        sb.append("]");
        if (isUid) {
            sb.append(",\"app_ids\":[").append(appIds).append("]");
        }
        sb.append(",\"data_source\":{\"type\":\"" + dataSourceType + "\",\"sub_type\":\"" + dataSourceSubtype + "\"}}");
        return sb.toString();
    }

    /**
     * 修改名称
     *
     * @param customAudienceTemplate
     * @param customAudiences
     */
    private void changeCustomAudienceName(CustomAudienceTemplate customAudienceTemplate, String name, List<CustomAudienceItem> customAudiences, String version, String userId) {

        if(ListUtil.isNotEmpty(customAudiences))
        {
            for (CustomAudienceItem customAudience : customAudiences) {
                try{
                    customAudienceRdbService.updateVersionAndRequestQueueStatus(customAudience.getId(), version, 0);
                    Long customAudienceId = customAudience.getCustomAudienceId();
                    Long fbAccountId = customAudience.getFbAccountId();
                    String token = fbUserRdbService.getTokenByUserId(userId);
                    if(token != null && !token.equals("")){
                        CustomAudienceParam customAudienceParam = new CustomAudienceParam();
                        Map<String, String> equipment = new HashMap<>();
                        equipment.put("templateId", customAudienceTemplate.getId() + "");
                        equipment.put("customAudienceDbId", customAudience.getId() + "");
                        equipment.put("customAudienceId", customAudienceId + "");
                        equipment.put("version", version);
                        customAudienceParam.setEquipment(equipment);
                        customAudienceParam.setId(customAudienceId);
                        customAudienceParam.setName(name);
                        customAudienceParam.setCallBack(true);
                        customAudienceParam.setApiCallbackTargetType(ApiCallBackTarget.CustomAudience.UpdateCustomaudienceName.getTargetType());
                        customAudienceParam.setApiPriorityCode(APIPriority.FetchCustomaudiences.getCode());
                        customAudienceParam.setFbAccountId(fbAccountId);
                        customAudienceParam.setAccessToken(token);
                        customaudiencesFbServices.updateCustomAudience(customAudienceParam);
                    }
                }catch (Exception e){
                    logger.error("call facebook customaudience interface fail!,customAudienceId:",customAudience.getId());
                }
            }
        }
    }

    @Override
    public List<CustomAudienceItem> getCustomAudienceItemList(String userId,Long customAudienceTemplateId) {
        return customAudienceRdbService.getCustomAudienceItemListByTemplateId(userId,customAudienceTemplateId);
    }

    @Override
    public List<CustomAudienceTemplate> findByOrgId(Long orgId, String userId)
    {
        return customAudienceTemplateRdbService.findCanUseTmpl(orgId, userId);
    }


    @Override
    public List<Long> findHasLookALike(List<Long> ids) {
        return customAudienceTemplateRdbService.findHasLookALike(ids);
    }

    @Override
    public List<CustomAudienceTemplateTable> getAllCustomAudienceTemplate(Long orgId, String audienceType, String importedType) {
        return customAudienceTemplateRdbService.getAllCustomAudienceTemplate(orgId,audienceType,importedType);
    }

    @Override
    public List<CustomAudienceTemplateTable> getAllLookAlikeList(QueryLookALikeParam queryLookALikeParam, User user) {
        return customAudienceTemplateRdbService.findAllLookAlikeByUserIdAndName(user.getOrgId(),queryLookALikeParam.getName());
    }

}
